package com.xky.example_student.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xky.example_student.entity.Result;
import com.xky.example_student.entity.Score;
import com.xky.example_student.entity.ScoreStatistics;
import com.xky.example_student.mapper.ScoreMapper;
import com.xky.example_student.service.ScoreService;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.*;
import java.util.*;
import java.util.stream.Collectors;

import static com.xky.example_student.entity.Result.error;

@Service
@Slf4j
public class ScoreServiceImpl extends ServiceImpl< ScoreMapper,Score> implements ScoreService {

    @Autowired
    private ScoreMapper scoreMapper;


    @Override
    public byte[] generateExcel(List<Score> scores) throws IOException {
        try (Workbook workbook = new XSSFWorkbook()) {
            Sheet sheet = workbook.createSheet("成绩表");
            Row headerRow = sheet.createRow(0);
            String[] headers = {"ID", "学号", "学生姓名", "学期", "课程序号", "课程名称", "分数", "学分", "成绩类别"};
            for (int i = 0; i < headers.length; i++) {
                Cell cell = headerRow.createCell(i);
                cell.setCellValue(headers[i]);
            }

            for (int i = 0; i < scores.size(); i++) {
                Score score = scores.get(i);
                Row row = sheet.createRow(i + 1);
                row.createCell(0).setCellValue(score.getId());
                row.createCell(1).setCellValue(score.getStuId());
                row.createCell(2).setCellValue(score.getStuName());
                row.createCell(3).setCellValue(score.getTeam());
                row.createCell(4).setCellValue(score.getCourseSerialNumber());
                row.createCell(5).setCellValue(score.getCourseName());
                row.createCell(6).setCellValue(score.getScore());
                row.createCell(7).setCellValue(score.getCredit());
                row.createCell(8).setCellValue(score.getGradeCategory());
            }

            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            workbook.write(outputStream);
            return outputStream.toByteArray();
        }
    }

    @Override
    public Integer sumScore(String name) {
        LambdaQueryWrapper<Score> scoreLambdaQueryWrapper = new LambdaQueryWrapper<>();
        scoreLambdaQueryWrapper.eq(Score::getStuName,name);
        List<Score> scores = scoreMapper.selectList(scoreLambdaQueryWrapper);
        int sum = 0;
        for (Score score : scores){
            Integer score1 = score.getScore();
            sum+=score1;
        }
        return sum;
    }

    @Override
    public List<ScoreStatistics> calculateStudentAverages(Long studentId) {
        try {
            log.info("开始计算学生ID: {} 的成绩统计", studentId);
            // 获取学生的所有成绩
            LambdaQueryWrapper<Score> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(Score::getStuId, studentId);
            List<Score> scores = list(wrapper);
            
            if (scores.isEmpty()) {
                log.warn("未找到学生ID: {} 的成绩记录", studentId);
                return new ArrayList<>();
            }
            
            log.info("找到 {} 条成绩记录", scores.size());
            return calculateStatistics(scores);
        } catch (Exception e) {
            log.error("计算学生成绩统计失败", e);
            throw new RuntimeException("计算成绩统计失败: " + e.getMessage());
        }
    }

    @Override
    public List<ScoreStatistics> calculateAllAverages() {
        try {
            log.info("开始计算所有学生的成绩统计");
            // 获取所有成绩
            List<Score> scores = list();
            
            if (scores.isEmpty()) {
                log.warn("数据库中没有成绩记录");
                return new ArrayList<>();
            }
            
            log.info("找到 {} 条成绩记录", scores.size());
            return calculateStatistics(scores);
        } catch (Exception e) {
            log.error("计算所有成绩统计失败", e);
            throw new RuntimeException("计算成绩统计失败: " + e.getMessage());
        }
    }


    @Override
    public float creditScoreCalculation(Integer stuId) {
        LambdaQueryWrapper<Score> scoreLambdaQueryWrapper = new LambdaQueryWrapper<>();
        scoreLambdaQueryWrapper.eq(Score::getStuId,stuId);
        List<Score> scores = scoreMapper.selectList(scoreLambdaQueryWrapper);
        if (scores.isEmpty()){
            log.warn("数据库中没有成绩记录");
            return 0;
        }
        
        // 计算加权平均分（学分绩）
        double totalWeightedScore = 0;
        double totalCredits = 0;
        
        for (Score score : scores){
            if (score.getScore() != null && score.getCredit() != null && score.getCredit() > 0) {
                totalWeightedScore += score.getScore() * score.getCredit();
                totalCredits += score.getCredit();
            }
        }
        
        if (totalCredits == 0) {
            log.warn("学号为{}的学生没有有效的学分记录", stuId);
            return 0;
        }
        
        float creditGPA = (float) (totalWeightedScore / totalCredits);
        log.info("学号为{}的学生学分绩计算结果: {}", stuId, creditGPA);
        return creditGPA;
    }
    
    @Override
    public void updateStudentCreditScores(Integer stuId) {
        // 计算该学生的学分绩
        float creditScore = creditScoreCalculation(stuId);
        
        // 更新该学生的所有成绩记录的学分绩字段
        LambdaUpdateWrapper<Score> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(Score::getStuId, stuId)
                    .set(Score::getCreditScore, creditScore);
        this.update(updateWrapper);
        
        log.info("已更新学号为{}的学生的学分绩: {}", stuId, creditScore);
    }
    
    @Override
    public void updateAllCreditScores() {
        // 获取所有不同的学生学号
        List<Integer> allStuIds = this.list().stream()
                .map(Score::getStuId)
                .distinct()
                .collect(Collectors.toList());
        
        log.info("开始更新所有学生的学分绩，共{}名学生", allStuIds.size());
        
        // 为每个学生更新学分绩
        for (Integer stuId : allStuIds) {
            updateStudentCreditScores(stuId);
        }
        
        log.info("所有学生的学分绩更新完成");
    }

    private List<ScoreStatistics> calculateStatistics(List<Score> scores) {
        return scores.stream()
            .collect(Collectors.groupingBy(
                score -> new AbstractMap.SimpleEntry<>(score.getTeam(), score.getCourseName()),
                Collectors.collectingAndThen(
                    Collectors.toList(),
                    courseScores -> {
                        DoubleSummaryStatistics scoreStats = courseScores.stream()
                            .mapToDouble(score -> score.getScore() != null ? score.getScore() : 0)
                            .summaryStatistics();
                        
                        double totalWeightedScore = courseScores.stream()
                            .mapToDouble(score -> 
                                (score.getScore() != null ? score.getScore() : 0) * 
                                (score.getCredit() != 0 ? score.getCredit() : 0))
                            .sum();
                        
                        double totalCredits = courseScores.stream()
                            .mapToDouble(score -> score.getCredit() != 0 ? score.getCredit() : 0)
                            .sum();

                        return ScoreStatistics.builder()
                            .team(courseScores.get(0).getTeam())
                            .courseName(courseScores.get(0).getCourseName())
                            .averageScore(scoreStats.getAverage())
                            .weightedAverage(totalCredits > 0 ? totalWeightedScore / totalCredits : 0)
                            .maxScore(scoreStats.getMax())
                            .minScore(scoreStats.getMin())
                            .count((int)scoreStats.getCount())
                            .totalCredits(totalCredits)
                            .build();
                    }
                )
            ))
            .values()
            .stream()
            .sorted(Comparator.comparing(ScoreStatistics::getTeam)
                .thenComparing(ScoreStatistics::getCourseName))
            .collect(Collectors.toList());
    }
}
